package influence.propagation.swing.implementation;

import influence.propagation.core.Model;
import influence.propagation.core.NodeModel;
import influence.propagation.core.OutputMode;
import influence.propagation.core.ResultSet;
import influence.propagation.exception.InputFormatException;
import influence.propagation.implementation.ModelFactory;
import influence.propagation.implementation.RelType;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Map;

import org.graphstream.graph.Graph;
//import org.graphstream.graph.Node;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.graphdb.DynamicLabel;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.ResourceIterator;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;

public class Controller {
	
	private GraphDatabaseService db;
	private Model model;
	private ResultSet rs;
	private int it = 0;
	private int occ = 0;
	
	public static enum ModelType{
		INDIPENDENT_CASCADE;
	}
	
	public void closeDb(){
		if (db != null) {
			db.shutdown();
		}
	}
	
	public void drawGraph(Graph g){
		try (Transaction tx = db.beginTx()) {
			ExecutionEngine ee = new ExecutionEngine(db);
			ResourceIterator<Map<String, Object>> ri=ee.execute("match (n) return n").iterator();
			while (ri.hasNext()) {
				Map<String, Object> map = ri.next();
				for (String key : map.keySet()) {
					Node node = (Node) map.get(key);
					Long id = node.getId();
					String name = (String) node.getProperty("NAME");
					boolean isActive = node.hasLabel(DynamicLabel
							.label("ACTIVE"));
					org.graphstream.graph.Node gNode = g.addNode(id.toString());
					gNode.addAttribute("ui.label", name);
					System.out.println(id);
					if (isActive) {
						gNode.addAttribute("ui.class", "active");
					}
				}// for
			}// while
			ri.close();
			ri = ee.execute("match ()-[r]->() return r").iterator();
			while (ri.hasNext()) {
				Map<String, Object> map = ri.next();
				for (String key : map.keySet()) {
					Relationship r = (Relationship) map.get(key);
					Long idNode1 = r.getStartNode().getId();
					Long idNode2 = r.getEndNode().getId();
					g.addEdge(new Long(r.getId()).toString(),
							idNode1.toString(), idNode2.toString(), true)
							.addAttribute(
									"ui.label",
									r.getProperty(RelType
											.wheightPropertyKeyName()));
					;
				}//for
			}//while
			ri.close();
			tx.success();
		}//try
	}
	
	public Controller(ModelType mode, File ... f){
		switch (mode) {
		case INDIPENDENT_CASCADE:
			if(f.length != 2){
				throw new IllegalArgumentException("i file devono essere 2");
			}
			if(db==null){
				instanziateDb();
			}
			try {
				model = ModelFactory.createNewIndependentCascadeModel(db, f[0], f[1]);
			} catch (FileNotFoundException
					| influence.propagation.exception.IllegalArgumentException
					| InputFormatException e) {
				e.printStackTrace();
			}
			break;
		default:
			break;
		}
	}
	
	public void executeAlgoritm(){
		rs = model.executeAlgoritm(OutputMode.BREADTH);
		System.out.println(rs);
	}

	public void stepNext(Graph g){
		control();
		if(it < rs.getIterations()){
			if(occ < rs.getOccurence(it)){
				next(g , rs.get(it, occ));
				occ++;
			}
			else{
				occ=0;
				it++;
				if(it<rs.getIterations()){
					next(g, rs.get(it, occ));
				}
			}
		}
	}

	public void stepBack(Graph g){
		control();
		if(it > 0){
			if(occ > 0){
				occ--;
				back(g, rs.get(it, occ));
			}else{
				it--;
				if(it>0){
					occ = rs.getOccurence(it);
					back(g, rs.get(it, occ));
				}
			}
		}
	}
	
	private void back(Graph g, NodeModel nodeModel) {
		g.getNode(nodeModel.getId().toString()).removeAttribute("ui.class");
		
	}
	
	private void next(Graph g, NodeModel nodeModel) {
		Long id = nodeModel.getId();
		System.out.println(nodeModel);
		System.out.println(id);
		org.graphstream.graph.Node node = g.getNode(id.toString());
		node.addAttribute("ui.class","active");
	}

	private void instanziateDb() {
		db = new GraphDatabaseFactory().newEmbeddedDatabase("C:\\Users\\Valerio\\Documents\\Neo4j\\databaseTesi");
	}
	
	private void control() {
		if(rs == null){
			throw new IllegalStateException();
		}
	}
}
